<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * Class BaseModel  基础模型类
 * @package App\Models
 */
class BaseModel extends Model
{
    use SoftDeletes;

    /**
     * $tableName 获取数据表的完整名称
     * @var null
     */
    protected $tableName = null;

    /**
     * $listOrder 默认列表排序
     * @var string
     */
    public $listOrder = 'created_at';

    /**
     * 修改字段的黑名单
     * @var array
     */
    protected $guarded = [];

    /**
     * $listFields 列表显示字段
     * @var string[]
     */
    public $listFields = ['*'];

    /**
     * $readFields 详情显示字段
     * @var string[]
     */
    public $readFields = ['*'];

    /**
     * getTableColumn 获取数据表的所有字段
     * @return array
     */
    public function getTableColumn(): array
    {
        if (empty($this->tableName)) {
            return [];
        }
        return Schema::getColumnListing($this->tableName);
    }

    /**
     * updateBatch 批量更新
     * @param array $multipleData
     * @return bool|int
     */
    public function updateBatch($multipleData = [])
    {
        try {
            if (empty($multipleData)) {
                throw new \Exception("数据不能为空");
            }
            $tableName = DB::getTablePrefix() . $this->getTable(); // 表名
            $firstRow  = current($multipleData);

            $updateColumn = array_keys($firstRow);
            // 默认以id为条件更新，如果没有ID则以第一个字段为条件
            $referenceColumn = isset($firstRow['id']) ? 'id' : current($updateColumn);
            unset($updateColumn[0]);
            // 拼接sql语句
            $updateSql = "UPDATE " . $tableName . " SET ";
            $sets      = [];
            $bindings  = [];
            foreach ($updateColumn as $uColumn) {
                $setSql = "`" . $uColumn . "` = CASE ";
                foreach ($multipleData as $data) {
                    $setSql .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
                    $bindings[] = $data[$referenceColumn];
                    $bindings[] = $data[$uColumn];
                }
                $setSql .= "ELSE `" . $uColumn . "` END ";
                $sets[] = $setSql;
            }
            $updateSql .= implode(', ', $sets);
            $whereIn   = collect($multipleData)->pluck($referenceColumn)->values()->all();
            $bindings  = array_merge($bindings, $whereIn);
            $whereIn   = rtrim(str_repeat('?,', count($whereIn)), ',');
            $updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
            // 传入预处理sql语句和对应绑定数据
            return DB::update($updateSql, $bindings);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * 批量插入或更新表中数据
     *
     * @param $data 要插入的数据，元素中的key为表中的column，value为对应的值
     * @param string $table 要插入的表
     * @param array $columns 要更新的的表的字段
     * @return array
     */
    public function batchInsertOrUpdate($data, $table = '',$columns = []){

        if(empty($data)){//如果传入数据为空 则直接返回
            return [
                'insertNum' => 0,
                'updateNum' => 0
            ];
        }

        empty($table) && $table = $this->getTable();  //如果未传入table则通过对象获得
        empty($columns) && $columns = $this->getTableColumns();  //如果未传入table则通过对象获得

        //拼装sql
        $sql = "insert into ".$table." (";
        foreach ($columns as $k => $column) {
            $sql .= $column ." ,";
        }
        $sql = trim($sql,',');
        $sql .= " ) values ";

        foreach ($data as $k => $v){
            $sql .= "(";
            foreach ($columns as $kk => $column){
                if('updated_at' == $column){ //如果库中存在，create_at字段会被更新
                    $sql .= " '".date('Y-m-d H:i:s')."' ,";
                }else{
                    $val = ''; //插入数据中缺少$colums中的字段时的默认值
                    if(isset($v[$column])){
                        $val = $v[$column];
                        $val = addslashes($val);  //在预定义的字符前添加反斜杠的字符串。
                    }
                    $sql .= " '".$val."' ,";
                }
            }
            $sql = trim($sql,',');
            $sql .= " ) ,";
        }
        $sql = trim($sql,',');
        $sql .= "on duplicate key update ";
        foreach ($columns as $k => $column){
            $sql .= $column ." = values (".$column.") ,";
        }
        $sql = trim($sql,',');
        $sql .= ';';

        $columnsNum = count($data);
        $retNum = DB::update(DB::raw($sql));
        $updateNum = $retNum - $columnsNum;
        $insertNum = $columnsNum - $updateNum;
        return [
            'insertNum' => $insertNum,
            'updateNum' => $updateNum
        ];
    }
}
